/******************************************************************************/
/*                                                                            */
/*  File: xtxtloader.cpp                                                      */
/*  Author: bkenwright@xbdev.net                                              */
/*  URL: www.xbdev.net                                                        */
/*                                                                            */
/******************************************************************************/
/*

*/
/******************************************************************************/

#include <stdio.h>
#include <string>

//#include "common\common.h"
//#include "common\darray.h"



#include "tokenparser.h"
#include "xtxtloader.h"




void ParseData(TokenParser& tokenParser, stXBase* xBase);


/******************************************************************************/

int GetXStringID(const char* str)
{
	int itemId = -1;
	DBG_ASSERT(str);
	int numTypes = sizeof(xtxttypes)/sizeof(stDefines);
	for (int ii=0; ii<numTypes; ii++)
	{
		if (_stricmp(xtxttypes[ii].name, str)==0)
		{
			itemId=xtxttypes[ii].id;
			break;
		}
	}
	return itemId;
}


void SkipBlock(TokenParser& tokenParser)
{
	stToken* token = tokenParser.GetToken();
	DBG_ASSERT(token);

	if (token->GetType()==stToken::TokenString)
	{
		token = tokenParser.GetNextToken();
		DBG_ASSERT(token);
	}

	int depth = 0;
	while (true)
	{
		token = tokenParser.GetNextToken();
		DBG_ASSERT(token);

		if (token->GetType()==stToken::TokenCloseB && depth==0)
		{
			break;
		}

		if (token->m_tokenType==stToken::TokenOpenB)
		{
			depth++;
		}
		if (token->m_tokenType==stToken::TokenCloseB)
		{
			depth--;
		}
	}
}

/******************************************************************************/

void ReadXOF(TokenParser& tokenParser)
{
	/*
	xof 0303txt 0064
	*/

	stToken* token = NULL;

	token = tokenParser.GetToken(); //"xof"
	DBG_ASSERT(token->GetType()==stToken::TokenString);

	token = tokenParser.GetNextToken(); //"0303txt"
	DBG_ASSERT(token->GetType()==stToken::TokenString);

	token = tokenParser.GetNextToken(); //"0064"
	DBG_ASSERT(token->GetType()==stToken::TokenNumber);
}

/******************************************************************************/

void ReadHEADER(TokenParser& tokenParser, stXBase* xBase)
{
	DBG_ASSERT(xBase);
	DBG_ASSERT(xBase->GetType()==X_FILE);

	/*
	Header {
		1;
		0;
		1;
	}
	*/

	stToken* token = NULL;

	token = tokenParser.GetNextToken(); //Open Braces
	DBG_ASSERT(token->GetType()==stToken::TokenOpenB);

	for (int i=0; i<3; i++)
	{
		token = tokenParser.GetNextToken(); //Open Braces
		DBG_ASSERT(token->GetType()==stToken::TokenNumber);

		token = tokenParser.GetNextToken(); //Open Braces
		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);
	}

	token = tokenParser.GetNextToken(); //Open Braces
	DBG_ASSERT(token->GetType()==stToken::TokenCloseB);
}

/******************************************************************************/

void ReadXTEMPLATE(TokenParser& tokenParser, stXBase* xBase)
{
	DBG_ASSERT(xBase);
	DBG_ASSERT(xBase->GetType()==X_FILE);

	stToken* token = NULL;
	
	token = tokenParser.GetNextToken(); //Name Template
	DBG_ASSERT(token->GetType()==stToken::TokenString);
	token = tokenParser.GetNextToken(); //Open Braces
	DBG_ASSERT(token->GetType()==stToken::TokenOpenB);

	SkipBlock(tokenParser);

	token = tokenParser.GetToken();
	DBG_ASSERT(token->GetType()==stToken::TokenCloseB);
}

/******************************************************************************/

void ReadXFRAMETRANSFORMMATRIX(TokenParser& tokenParser, stXBase* xBase)
{
	DBG_ASSERT(xBase);
	DBG_ASSERT(xBase->GetType()==X_FRAME);

	stXFrame* xFrame = static_cast<stXFrame*>(xBase);
	DBG_ASSERT(xFrame);

	/*
	FrameTransformMatrix {
		0.000001,0.000000,1.000000,0.000000,
		1.000000,-0.000000,-0.000001,0.000000,
		0.000000,1.000000,-0.000000,0.000000,
		0.233847,39.526119,-1.626864,1.000000;;
	}
	*/

	stToken* token = NULL;

	token = tokenParser.GetNextToken(); //Open Braces
	DBG_ASSERT(token->GetType()==stToken::TokenOpenB);

	for (int i=0; i<16; i++)
	{
		token = tokenParser.GetNextToken(); // Number
		DBG_ASSERT(token->GetType()==stToken::TokenNumber);

		float val = (float)atof(token->m_data);
		xFrame->m_mat[i] = val;


		token = tokenParser.GetNextToken(); // , or ;
	}

	token = tokenParser.GetNextToken(); // Number
	DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);


	token = tokenParser.GetNextToken();
	DBG_ASSERT(token->GetType()==stToken::TokenCloseB);
}

/******************************************************************************/

void ReadXFRAME(TokenParser& tokenParser, stXBase* xBase)
{
	DBG_ASSERT(xBase);
	DBG_ASSERT(xBase->GetType()==X_FRAME);

	stXFrame* xFrame = static_cast<stXFrame*>(xBase);
	DBG_ASSERT(xFrame);


	stToken* token = NULL;

	token = tokenParser.GetNextToken(); //Name { Optional }

	switch (token->GetType())
	{
		case stToken::TokenString:
		{
			int len = (int)strlen(token->m_data);
			DBG_ASSERT(len<127);
			strcpy_s(xFrame->m_name, token->m_data);

			token = tokenParser.GetNextToken(); //Open Braces
			DBG_ASSERT(token->GetType()==stToken::TokenOpenB);
		}
		break;

		case stToken::TokenOpenB:
		{
		}
		break;

		default:
		{
			DBG_HALT;
		}
	}
	DBG_ASSERT(token->GetType()==stToken::TokenOpenB);

	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenString);

	ParseData(tokenParser, xBase);

	token = tokenParser.GetToken();
	DBG_ASSERT(token->GetType()==stToken::TokenCloseB);
}
/******************************************************************************/

void ReadXANIMATIONKEY(TokenParser& tokenParser, stXBase* xBase)
{
	DBG_ASSERT(xBase);
	DBG_ASSERT(xBase->GetType()==X_ANIMATIONKEY);

	stXAnimationKey* aKey = static_cast<stXAnimationKey*>(xBase);
	DBG_ASSERT(aKey);

	stToken* token = NULL;

	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenOpenB);
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);
	int num = atoi(token->m_data);
	DBG_ASSERT(num>0 && num<10000); // Sanity Check
	DBG_ASSERT(num==4);
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);

	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);
	int numFrames = atoi(token->m_data);
	DBG_ASSERT(numFrames>0 && numFrames<10000); // Sanity Check
	aKey->m_numFrames = numFrames;

	aKey->m_mat = new D3DXMATRIX[numFrames];

	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);

	for (int i=0; i<numFrames; i++)
	{
		token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);
		token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);

		token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);
		int matItems = atoi(token->m_data);
		DBG_ASSERT(matItems==16);
		token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);

		D3DXMATRIX& mat = aKey->m_mat[i];

		for (int k=0; k<16; k++)
		{
			token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);

			float val = (float)atof(token->m_data);
			DBG_ASSERT(val>-999999  && val <9999999);
			mat[k] = val;

			if (k<16-1)	
			{ 
				token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenComma);		
			}
		}
		token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);
		token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);

		if (i<numFrames-1)
		{
			token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenComma);
		}
	}
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);

	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenCloseB);
}


/******************************************************************************/

void ReadXANIMATIONOPTIONS(TokenParser& tokenParser, stXBase* xBase)
{
	DBG_ASSERT(xBase);
	DBG_ASSERT(xBase->GetType()==X_ANIMATIONSET);

	/*
	  AnimationOptions {
		   1;
		   0;
		  }
	*/

	stToken* token = NULL;
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenOpenB);
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);

	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenCloseB);
}

/******************************************************************************/

void ReadXANIMATION(TokenParser& tokenParser, stXBase* xBase)
{
	/*
	 Animation Name {		// Name {OPTIONAL}
		 {Bip01_L_Arm1}		// {OPTIONAL}
		 AnimationKey {
		  4;
		  24;
		  1,
		  2;
		  }
		  {Bip01_L_Arm1}	// {OPTIONAL}
	  }
	*/


	DBG_ASSERT(xBase);
	DBG_ASSERT(xBase->GetType()==X_ANIMATIONSET);

	stXAnimSet* xAnimSet = static_cast<stXAnimSet*>(xBase);
	DBG_ASSERT(xAnimSet);

	stXAnimation* anim = new stXAnimation();
	xAnimSet->AddAnimation(anim);




	stToken* token = NULL;

	token = tokenParser.GetNextToken();

	// Has Name?
	// 'NameSr' or '{'
	switch (token->GetType())
	{
		case stToken::TokenString:
		{
			int len = (int)strlen(token->m_data);
			DBG_ASSERT(len<127);
			strcpy_s(anim->m_name, token->m_data);

			token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenOpenB);
		}
		break;

		case stToken::TokenOpenB:
		{
		}
		break;

		default: { DBG_HALT; }
	}

	DBG_ASSERT(token->GetType()==stToken::TokenOpenB);

	token = tokenParser.GetNextToken();

	// Has sub name '{Bip01_L_Arm1}' or 'AnimationKey'
	switch (token->GetType())
	{
		case stToken::TokenString:
		{
			bool isAnimKey = strcmp(token->m_data, "AnimationKey")==0;
			DBG_ASSERT(isAnimKey);
		}
		break;

		case stToken::TokenOpenB:
		{
			token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenString);

			int len = (int)strlen(token->m_data);
			DBG_ASSERT(len<127);
			strcpy_s(anim->m_skinName, token->m_data);


			token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenCloseB);
			token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenString);
		}
		break;

		default: {DBG_HALT; }
	}

	DBG_ASSERT(token->GetType()==stToken::TokenString);

	bool isAnimationOptions = strcmp(token->m_data, "AnimationOptions")==0;
	if (isAnimationOptions)
	{
		ReadXANIMATIONOPTIONS(tokenParser, xBase);
		token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenString);
	}


	bool isAnimationKey = strcmp(token->m_data, "AnimationKey")==0;
	DBG_ASSERT(isAnimationKey);

	DBG_ASSERT(anim->m_animKey==NULL);
	anim->m_animKey = new stXAnimationKey();

	// Read AnimationKeys directly because of the way there setup
	ReadXANIMATIONKEY(tokenParser, anim->m_animKey);

	token = tokenParser.GetNextToken();
	switch (token->GetType())
	{
		case stToken::TokenOpenB:
		{
			token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenString);
			token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenCloseB);
			token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenCloseB);
		}
		break;

		case stToken::TokenCloseB:
		{
		}
		break;

		default: { DBG_HALT; }
	}


	token = tokenParser.GetToken();
	DBG_ASSERT(token->GetType()==stToken::TokenCloseB);

}

/******************************************************************************/

void ReadXANIMATIONSET(TokenParser& tokenParser, stXBase* xBase)
{
	DBG_ASSERT(xBase);
	DBG_ASSERT(xBase->GetType()==X_ANIMATIONSET);

	stToken* token = NULL;

	stXAnimSet* xAnimSet = static_cast<stXAnimSet*>(xBase);
	DBG_ASSERT(xAnimSet);

	token = tokenParser.GetNextToken();
	switch (token->GetType())
	{
		case stToken::TokenString:
		{
			int len = (int)strlen(token->m_data);
			DBG_ASSERT(len<127);
			strcpy_s(xAnimSet->m_name, token->m_data);
			token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenOpenB);
		}
		break;

		case stToken::TokenOpenB:
		{
		}
		break;

		default: { DBG_HALT; }
	}

	DBG_ASSERT(token->GetType()==stToken::TokenOpenB);
	token = tokenParser.GetNextToken();

	switch (token->GetType())
	{
		case stToken::TokenString:
		{
		}
		break;

		case stToken::TokenCloseB:
		{
			// Empty Anim Set Block!
			return;
		}
		break;

		default: { DBG_HALT; }
	}

	DBG_ASSERT(token->GetType()==stToken::TokenString);

	DBG_ASSERT( (token->GetType()==stToken::TokenString) || (token->GetType()==stToken::TokenCloseB));

	ParseData(tokenParser, xBase);

	token = tokenParser.GetToken();
	DBG_ASSERT(token->GetType()==stToken::TokenCloseB);
}

/******************************************************************************/

void ReadXTEXTUREFILENAME(TokenParser& tokenParser, stXBase* xBase)
{
	DBG_ASSERT(xBase);
	DBG_ASSERT(xBase->GetType()==X_MATERIAL);
	/*
	 TextureFilename {
		  "wall1_d.psd";
		 }
	*/

	stXMaterial* material = static_cast<stXMaterial*>(xBase);
	DBG_ASSERT(material);

	stXFile* xFile = (stXFile*)tokenParser.GetData();
	DBG_ASSERT(xFile);

	stToken* token = NULL;
	token = tokenParser.GetToken();

	bool same = (_stricmp("TextureFilename", token->m_data)==0);
	DBG_ASSERT(same);

	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenOpenB);
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenString);
	int len = (int)strlen(token->m_data);
	DBG_ASSERT(len>0 && len<128);
	DBG_ASSERT(material->m_hasTexture==false);
	strcpy_s(material->m_textureFileName, token->m_data);
	material->m_hasTexture = true;


	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenCloseB);
	
	//token = tokenParser.GetNextToken();
}

/******************************************************************************/

void ReadXEFFECTINSTANCE(TokenParser& tokenParser, stXBase* xBase)
{
	DBG_ASSERT(xBase);
	DBG_ASSERT(xBase->GetType()==X_MATERIAL);
	
	/*
	 EffectInstance {
		"Glow.fx";

		.. various effect things
	}
	*/
	stToken* token = NULL;
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenOpenB);
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenString);
	
	// Do a save of the effect filename here

	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);
	
	token = tokenParser.GetNextToken();

	switch (token->GetType())
	{
		case stToken::TokenString:
		{
			ParseData(tokenParser, xBase);

			DBG_ASSERT(token->GetType()==stToken::TokenCloseB);
		}
		break;

		case stToken::TokenCloseB:
		{
		}
		break;

		default:
		{
			DBG_HALT;
		}
	}

	DBG_ASSERT(token->GetType()==stToken::TokenCloseB);

}

/******************************************************************************/

void ReadXEFFECTPARAMSTRING(TokenParser& tokenParser, stXBase* xBase)
{
	DBG_ASSERT(xBase);
	DBG_ASSERT(xBase->GetType()==X_MATERIAL);

	/*
	EffectParamString {
	   "Tex0";
	   "wall1_d.psd";
	  }
	*/

	stToken* token = NULL;
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenOpenB);
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenString);
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenString);
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);
	

	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenCloseB);
}

/******************************************************************************/

void ReadXEFFECTPARAMDWORD(TokenParser& tokenParser, stXBase* xBase)
{
	DBG_ASSERT(xBase);
	DBG_ASSERT(xBase->GetType()==X_MATERIAL);

	/*
	  EffectParamDWord {
		   "LightDir";
		   0;
		  }
	*/

	stToken* token = NULL;
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenOpenB);
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenString);
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);

	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenCloseB);
}

/******************************************************************************/

void ReadXEFFECTPARAMFLOATS(TokenParser& tokenParser, stXBase* xBase)
{
	DBG_ASSERT(xBase);
	DBG_ASSERT(xBase->GetType()==X_MATERIAL);

	/*
	  EffectParamFloats {
		   "GlowColor";
		   4;
		   0.180392,
		   0.611765,
		   0.815686,
		   1.000000;
		  }
	*/

	stToken* token = NULL;
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenOpenB);
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenString);
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);

	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);
	int numFloats = atoi(token->m_data);
	DBG_ASSERT(numFloats>0 && numFloats<100);
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);

	for (int i=0; i<numFloats; i++)
	{
		if (i<numFloats-1)
		{
			token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);
			token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenComma);
		}
		else
		{
			token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);
			token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);
		}
	}

	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenCloseB);
}


/******************************************************************************/

void ReadXPATCH(TokenParser& tokenParser, stXBase* xBase)
{
	DBG_ASSERT(xBase);
	//DBG_ASSERT(xBase->GetType()==X_PATCHMESH);

	/*
	Patch{
		3;
		0,
		1,
		2;
	}
	*/

	stToken* token = NULL;
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenOpenB);

	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);
	int numPoints = atoi(token->m_data);
	DBG_ASSERT(numPoints>0 && numPoints<1000);
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);

	for (int i=0; i<numPoints; i++)
	{
		token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);

		if (i<numPoints-1)	{ token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenComma);		}
		else				{ token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);	}
	}

	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenCloseB);
}

/******************************************************************************/

void ReadXPATCHMESH(TokenParser& tokenParser, stXBase* xBase)
{
	DBG_ASSERT(xBase);
	/*
	
	PatchMesh nameOfPatch {
		3;
		-27.15,-0.00,12.99;,
		-33.69,-0.00,6.80;,
		-38.76,0.00,-0.38;,

		1;
		Patch{
		2;
		0,
		1;
		}
	}
	*/

	stToken* token = NULL;
	token = tokenParser.GetNextToken(); //Name or Inline(hence no name)

	switch (token->GetType())
	{
		case stToken::TokenString:
		{
			const char* patchName = token->m_data;
			DBG_ASSERT(patchName);
			DBG_ASSERT(strlen(patchName)<127);

			token = tokenParser.GetNextToken(); //Open Braces
			DBG_ASSERT(token->GetType()==stToken::TokenOpenB);
		}
		break;

		case stToken::TokenOpenB:
		{
			// Generate unique default name and store & assign it
		}
		break;

		default: { DBG_HALT; }
	}

	DBG_ASSERT(token->GetType()==stToken::TokenOpenB);

	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);
	int numVerts = atoi(token->m_data);
	DBG_ASSERT(numVerts>0 && numVerts<1000);
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);

	for (int i=0; i<numVerts; i++)
	{
		for (int k=0; k<3; k++)
		{
			token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);

			if (k<3-1)	{ token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenComma);		}
			else		{ token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);	}
		}

		if (i<numVerts-1)	{ token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenComma);		}
		else				{ token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);	}
	}

	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);
	int numPatches = atoi(token->m_data);
	DBG_ASSERT(numVerts>0 && numPatches<1000);
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);

	for (int i=0; i<numPatches; i++)
	{
		token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenString);
		DBG_ASSERT(strcmp(token->m_data, "Patch")==0);

		ReadXPATCH(tokenParser, xBase);

		token = tokenParser.GetToken();		DBG_ASSERT(token->GetType()==stToken::TokenCloseB);
	}

	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenCloseB);
}

/******************************************************************************/

void ReadXMATERIAL(TokenParser& tokenParser, stXBase* xBase)
{
	DBG_ASSERT(xBase);
	DBG_ASSERT(xBase->GetType()==X_MATERIAL);

	stXMaterial* material = static_cast<stXMaterial*>(xBase);
	DBG_ASSERT(material);

	stXFile* xFile = (stXFile*)tokenParser.GetData();
	DBG_ASSERT(xFile);

	IDirect3DDevice9* pDevice = xFile->m_pD3DDevice;
	DBG_ASSERT(pDevice);

	/*
	Material body {
		0.819608;0.756863;0.588235;1.000000;;
		0.000000;
		0.000000;0.000000;0.000000;;
		0.000000;0.000000;0.000000;;

		TextureFilename {
		"BODY.jpg";
		}
	}

	or

	Material {
		0.109804;0.584314;0.694118;1.000000;;
		0.000000;
		0.109804;0.584314;0.694118;;
		0.000000;0.000000;0.000000;;
	}
	*/

	stToken* token = NULL;
	token = tokenParser.GetNextToken(); //Name or Inline(hence no name)

	switch (token->GetType())
	{
		case stToken::TokenString:
		{
			const char* matName = token->m_data;
			DBG_ASSERT(matName);
			DBG_ASSERT(strlen(matName)<127);
			strcpy_s(material->m_name, matName);

			token = tokenParser.GetNextToken(); //Open Braces
			DBG_ASSERT(token->GetType()==stToken::TokenOpenB);
		}
		break;

		case stToken::TokenOpenB:
		{
			// Generate unique default name and store & assign it
		}
		break;

		default: { DBG_HALT; }
	}

	DBG_ASSERT(token->GetType()==stToken::TokenOpenB);

	// Face Colour
	for (int i=0; i<4; i++)
	{
		token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);

		float val = (float)atof(token->m_data);
		DBG_ASSERT(val>=0.0f && val<=1.0f);
		material->m_faceColourRGBA[i] = val;


		token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);
	}
	token = tokenParser.GetNextToken();
	DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);

	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);

	material->m_power = (float)atof(token->m_data);

	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);

	for (int i=0; i<3; i++)
	{
		token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);
		material->m_specularColourRGB[i] = (float)atof(token->m_data);
		token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);
	}
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);

	for (int i=0; i<3; i++)
	{
		token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);
		material->m_emmisiveColourRGB[i] = (float)atof(token->m_data);
		token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);
	}
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);


	token = tokenParser.GetNextToken();

	switch (token->GetType())
	{
		case stToken::TokenString:
		{
			/*
			bool same = (_stricmp("TextureFilename", token->m_data)==0);
			DBG_ASSERT(same);

			token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenOpenB);
			token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenString);
			int len = (int)strlen(token->m_data);
			DBG_ASSERT(len>0 && len<128);
			DBG_ASSERT(material->m_hasTexture==false);
			strcpy(material->m_textureFileName, token->m_data);
			material->m_hasTexture = true;


			token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);
			token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenCloseB);
			
			token = tokenParser.GetNextToken();
			*/



			ParseData(tokenParser, xBase);

			DBG_ASSERT(token->GetType()==stToken::TokenCloseB);
		}
		break;

		case stToken::TokenCloseB:
		{
		}
		break;

		default:
		{
			DBG_HALT;
		}
	}

	DBG_ASSERT(token->GetType()==stToken::TokenCloseB);
}

/******************************************************************************/

void ReadXMESHNORMALS(TokenParser& tokenParser, stXBase* xBase)
{
	DBG_ASSERT(xBase);
	DBG_ASSERT(xBase->GetType()==X_MESH);

	stXMesh* xMesh = static_cast<stXMesh*>(xBase);
	DBG_ASSERT(xMesh);


	/*
	MeshNormals  {
		3;
			0.000248;-0.984808;0.173645;,
			0.000248;-0.984808;0.173645;,
			0.000497;-0.984808;0.173645;;
		3;
			3;0,1,2;,
			3;3,4,5;,
			3;6,7,8;;
	}
	*/

	stToken* token = NULL;

	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenOpenB);
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);

	int numNormals = atoi(token->m_data);
	DBG_ASSERT(numNormals>=0 && numNormals<100000);
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);

	DBG_ASSERT(xMesh->m_numTris>0 || numNormals==0);
	DBG_ASSERT(xMesh->m_numNormals==0);


	D3DXVECTOR3* normals = new D3DXVECTOR3[ numNormals * 3 ]; // 3 Sides Triangle

	for (int i=0; i<numNormals; i++)
	{

			token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);
			float xval = (float)atof(token->m_data);
			token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);

			token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);
			float yval = (float)atof(token->m_data);
			token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);

			token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);
			float zval = (float)atof(token->m_data);
			token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);

			DBG_ASSERT(xval>-99999.0f && xval<999999.0f);
			DBG_ASSERT(yval>-99999.0f && yval<999999.0f);
			DBG_ASSERT(zval>-99999.0f && zval<999999.0f);

			normals[i].x = xval;
			normals[i].y = yval;
			normals[i].z = zval;


		if (i<numNormals-1)
		{
			token = tokenParser.GetNextToken();	DBG_ASSERT(token->GetType()==stToken::TokenComma);
		}		
	}
	token = tokenParser.GetNextToken();	DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);
	

	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);
	int numIndices = atoi(token->m_data);
	DBG_ASSERT(numIndices>=0 && numIndices<100000);
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);

	xMesh->m_numNormals = numIndices;
	
	for (int i=0; i<numIndices; i++)
	{
		token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);
		int indicesCount = atoi(token->m_data);
		DBG_ASSERT(indicesCount==3);
		token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);

		DBG_ASSERT(indicesCount==3);
		for (int k=0; k<3; k++)
		{
			token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);

			int val = atoi(token->m_data);
			DBG_ASSERT(val>=0 && val<numNormals);
			DBG_ASSERT(i>=0   && i<xMesh->m_numTris);

			xMesh->m_tris[i].normals[k] = normals[val];
		
			token = tokenParser.GetNextToken();		

			if (k==indicesCount-1)	{ DBG_ASSERT(token->GetType()==stToken::TokenSemiColon); }
			else					{ DBG_ASSERT(token->GetType()==stToken::TokenComma);	 }
		}

		if (i<numIndices-1)
		{
			token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenComma);	
		}		
	}

	delete[] normals;
	normals = NULL;

	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);


	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenCloseB);
}

/******************************************************************************/


void ReadXMESHMATERIALLIST(TokenParser& tokenParser, stXBase* xBase)
{
	DBG_ASSERT(xBase);
	DBG_ASSERT(xBase->GetType()==X_MESH);

	stXMesh* mesh = static_cast<stXMesh*>(xBase);
	DBG_ASSERT(mesh);

	DBG_ASSERT(mesh->m_matList==NULL);
	
	stXMaterialList* matList = new stXMaterialList();
	mesh->m_matList = matList;


	stXFile* xFile = (stXFile*)tokenParser.GetData();
	DBG_ASSERT(xFile);

	/*
	MeshMaterialList  {
		1;
		3;
		0,
		0,
		0;
		{ body }
	}

	or 

	MeshMaterialList  {
		1;
		0;
		;

		Material {...}		{ INLINE }
	}

	*/

	stToken* token = NULL;

	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenOpenB);
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);

	int numMaterials = atoi(token->m_data);
	DBG_ASSERT(numMaterials>0 && numMaterials<1000);
	matList->m_numMaterials = numMaterials;

	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);

	int num = atoi(token->m_data);
	DBG_ASSERT(num>=0 && num<100000);
	matList->m_numIndexes = num;
	matList->m_indexes = new int[num];

	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);

	for (int i=0; i<num; i++)
	{
		token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);

		int matIndex = atoi(token->m_data);
		DBG_ASSERT(matIndex>=0 && matIndex<100); // Sanity check
		matList->m_indexes[i] = matIndex;


		if (i<num-1)
		{
			token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenComma);
		}
	}
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);


	// Create temp array so we can update the array of which materials
	// refair to which material in the global material list
	int* newMatIds = new int[matList->m_numIndexes];
	for (int i=0; i<matList->m_numIndexes; i++)
	{
		newMatIds[i]=-1;
	}

	bool exitEarly = false;
	for (int i=0; i<numMaterials; i++)
	{
		token = tokenParser.GetNextToken();

		if (token->GetType()==stToken::TokenSemiColon)
		{
			token = tokenParser.GetNextToken();
		}

		stXMaterial* xMat = NULL;

		switch (token->GetType())
		{
			case stToken::TokenString: // Inline
			{
				if (_stricmp(token->m_data, "Material")==0)
				{
					
					xMat = xFile->m_materialManager.AddMaterial();
					ReadXMATERIAL(tokenParser, xMat);
				}
				else
				{
					DBG_HALT;
				}
			}
			break;

			case stToken::TokenOpenB: // Reference
			{
				//while (true)
				{
					token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenString);
					const char* matName = token->m_data;
					DBG_ASSERT(matName);

					xMat = xFile->m_materialManager.FindMaterial(matName);
					DBG_ASSERT(xMat);

					token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenCloseB);

					/*
					stToken* peekToken = tokenParser.PeekNextToken();
					if (peekToken->GetType()==stToken::TokenOpenB)
					{
						// Found another ref material
						token = tokenParser.GetNextToken();
					}
					else
					{
						break;
					}
					*/
				}
			}
			break;

			case stToken::TokenCloseB:
			{
				exitEarly = true;
			}
			break;

			default: { DBG_HALT; }
		}

		if (exitEarly) break;

		DBG_ASSERT(xMat);
		// Link our material to the list
		int numIndexes = matList->m_numIndexes;
		for (int k=0; k<numIndexes; k++)
		{
			int matRef = matList->m_indexes[k];
			if (matRef==i)
			{
				newMatIds[k]=xMat->m_id;
			}
		}

		
	}

	// Copy all our corrected material ids into the material list
	for (int i=0; i<matList->m_numIndexes; i++)
	{
		DBG_ASSERT(newMatIds[i]>=0);
		matList->m_indexes[i] = newMatIds[i];
	}

	for (int i=0; i<matList->m_numIndexes; i++)
	{
		DBG_ASSERT(matList->m_numIndexes == mesh->m_numTris);
		mesh->m_tris[i].matId = newMatIds[i];
	}


	delete[] newMatIds;
	newMatIds = NULL;


	if (exitEarly)
	{
		DBG_ASSERT(token->GetType()==stToken::TokenCloseB);
		return;
	}

	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenCloseB);

}

void ReadXMESHTEXTURECOORDS(TokenParser& tokenParser, stXBase* xBase)
{
	DBG_ASSERT(xBase);
	DBG_ASSERT(xBase->GetType()==X_MESH);

	stXMesh* xMesh = static_cast<stXMesh*>(xBase);
	DBG_ASSERT(xMesh);




	/*
	MeshTextureCoords  {
		84;
		0.805716;0.725244;,
		0.812639;0.764477;,
		0.808024;0.746014;;
		}
	*/

	stToken* token = NULL;

	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenOpenB);
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);

	int numTexs = atoi(token->m_data);
	DBG_ASSERT(numTexs>0 && numTexs<100000);
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);

	xMesh->m_numTexCoords = numTexs;
	DBG_ASSERT(xMesh->m_texCoords==NULL);
	xMesh->m_texCoords = new D3DXVECTOR2[ numTexs ];

	for (int i=0; i<numTexs; i++)
	{
		token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);
		float tu = (float)atof(token->m_data);
		token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);

		token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);
		float tv = (float)atof(token->m_data);
		token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);

		DBG_ASSERT(tu>-99999.0f && tu<99999.0f);
		DBG_ASSERT(tv>-99999.0f && tv<99999.0f);
		xMesh->m_texCoords[i].x = tu;
		xMesh->m_texCoords[i].y = tv;

		token = tokenParser.GetNextToken();	

		if (i==numTexs-1)	{ DBG_ASSERT(token->GetType()==stToken::TokenSemiColon); }
		else				{ DBG_ASSERT(token->GetType()==stToken::TokenComma);	 }
	}
	DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);

	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenCloseB);
}

void ReadXSKINWEIGHTS(TokenParser& tokenParser, stXBase* xBase)
{
	DBG_ASSERT(xBase);
	DBG_ASSERT(xBase->GetType()==X_MESH);

	stXMesh* mesh = static_cast<stXMesh*>(xBase);
	DBG_ASSERT(mesh);
	stXSkinWeights* skinWeights = new stXSkinWeights();
	mesh->AddSkinWeight(skinWeights);

	/*
	SkinWeights {
		"head_1";
		4;
		0,
		1,
		2,
		3;
		0.000000,
		0.000000,
		0.000000,
		0.000000;
		0.000383,-0.000000,0.364556,0.000000,
		0.000424,0.364556,0.000000,0.000000,
		-0.364556,0.000424,0.000383,0.000000,
		-0.610790,-24.768661,0.062114,1.000000;;
	}
	*/

	stToken* token = NULL;

	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenOpenB);
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenString);

	int len = (int)strlen(token->m_data);
	DBG_ASSERT(len<63);
	strcpy_s(skinWeights->m_name, token->m_data);

	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);

	int numIndxs = atoi(token->m_data);
	DBG_ASSERT(numIndxs>0 && numIndxs<100000);
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);

	skinWeights->m_numIndexes = numIndxs;
	skinWeights->m_indexes = new int[numIndxs];
	skinWeights->m_weights  = new float[numIndxs];

	for (int i=0; i<numIndxs; i++)
	{
		token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);

		int val = atoi(token->m_data);
		DBG_ASSERT(val>=0 && val<10000);
		skinWeights->m_indexes[i] = val;

		token = tokenParser.GetNextToken();	

		if (i==numIndxs-1)	{ DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);	}
		else				{ DBG_ASSERT(token->GetType()==stToken::TokenComma);		}
	}
	DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);
	
	for (int i=0; i<numIndxs; i++)
	{
		token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);

		float val = (float)atof(token->m_data);
		skinWeights->m_weights[i] = val;


		token = tokenParser.GetNextToken();		

		if (i==numIndxs-1)	{ DBG_ASSERT(token->GetType()==stToken::TokenSemiColon); }
		else				{ DBG_ASSERT(token->GetType()==stToken::TokenComma);     }
	}
	DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);

	// Read Matrix 4x4
	for (int i=0; i<16; i++)
	{
		token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);

		float val = (float)atof(token->m_data);
		skinWeights->m_mat[i] = val;

		token = tokenParser.GetNextToken();

		if (i==16-1)	{ DBG_ASSERT(token->GetType()==stToken::TokenSemiColon); }
		else			{ DBG_ASSERT(token->GetType()==stToken::TokenComma);     }
	}
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenCloseB);
}

void ReadXSKINMESHHEADER(TokenParser& tokenParser, stXBase* xBase)
{
	DBG_ASSERT(xBase);
	DBG_ASSERT(xBase->GetType()==X_MESH);

	/*
	XSkinMeshHeader {
		2;
		0;
		2;
	}
	*/

	stToken* token = NULL;

	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenOpenB);
	for (int i=0; i<3; i++)
	{
		token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);
		token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);
	}
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenCloseB);
}

/******************************************************************************/

void ReadXVERTEXDUPLICATIONINDICES(TokenParser& tokenParser, stXBase* xBase)
{
	DBG_ASSERT(xBase);
	DBG_ASSERT(xBase->GetType()==X_MESH);

	/*
	 VertexDuplicationIndices {
		 24;
		 8;
		 0,
		 1,
		 2,
		 3,
	 }
	 */

	
	stToken* token = NULL;

	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenOpenB);
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);

	int num = atoi(token->m_data);
	DBG_ASSERT(num>0 && num<5000); // Sanity check

	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);

	for (int i=0; i<num; i++)
	{
		token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);
		token = tokenParser.GetNextToken();

		if (i==num-1)	{ DBG_ASSERT(token->GetType()==stToken::TokenSemiColon); }
		else			{ DBG_ASSERT(token->GetType()==stToken::TokenComma);     }
	}

	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenCloseB);

}

/******************************************************************************/


void ReadXMESH(TokenParser& tokenParser, stXBase* xBase)
{
	DBG_ASSERT(xBase);
	DBG_ASSERT(xBase->GetType()==X_MESH);

	stXMesh* xMesh = static_cast<stXMesh*>(xBase);
	DBG_ASSERT(xMesh);

	/*
	Mesh  {
		3;
		-71.449913;79.331818;18.395760;,
		-71.449913;76.044464;-0.248118;,
		-61.984173;77.705307;9.144111;;
		2;
		3;0,1,2;,
		3;3,4,5;;

		MeshNormals					{ OPTIONAL }
		MeshMaterialList			{ OPTIONAL }
		MeshTextureCoords			{ OPTIONAL }
		XSkinMeshHeader				{ OPTIONAL }
		SkinWeights					{ OPTIONAL }
	}

	or

	Mesh  {
		0;
		;
		0;
		;
									{ OPTIONAL }
	}
	*/

	stToken* token = NULL;

	token = tokenParser.GetNextToken();
	switch ( token->GetType() )
	{
		case stToken::TokenString:
		{
			token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenOpenB);
		}
		break;

		case stToken::TokenOpenB:
		{
		}
		break;

		default: { DBG_HALT; }
	}

	DBG_ASSERT(token->GetType()==stToken::TokenOpenB);
	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);

	int numVerts = atoi(token->m_data);
	DBG_ASSERT(numVerts>=0 && numVerts<100000);

	xMesh->m_numVerts = numVerts;
	xMesh->m_verts = new D3DXVECTOR3[xMesh->m_numVerts];

	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);

	for (int i=0; i<numVerts; i++)
	{
		D3DXVECTOR3* v = &xMesh->m_verts[i];

		token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);
		v->x = (float)atof(token->m_data);
		token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);

		token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);
		v->y = (float)atof(token->m_data);
		token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);

		token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);
		v->z = (float)atof(token->m_data);
		token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);


		if (i<numVerts-1)
		{
			token = tokenParser.GetNextToken();	 DBG_ASSERT(token->GetType()==stToken::TokenComma);
		}
	}
	token = tokenParser.GetNextToken();	 DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);
	

	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);
	int numTris = atoi(token->m_data);
	DBG_ASSERT(numTris>=0 && numTris<100000);

	xMesh->m_numTris = numTris;
	xMesh->m_tris = new stXMesh::stTriData[numTris + 100]; // 100 is a saftey check

	token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);

	for (int i=0; i<numTris; i++)
	{
		token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);
		int indicesCount = atoi(token->m_data);
		DBG_ASSERT(indicesCount==3);

		token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);

		DBG_ASSERT(indicesCount==3);
		for (int k=0; k<indicesCount; k++)
		{
			token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenNumber);

			int val = atoi(token->m_data);
			DBG_ASSERT(val>=0 && val<numVerts); // Sanity Check
			DBG_ASSERT(k < 3);
			DBG_ASSERT(i < numTris);
			xMesh->m_tris[i].vertIndx[k] = val;

			token = tokenParser.GetNextToken();		
			
			if (k==indicesCount-1) { DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);	}
			else				   { DBG_ASSERT(token->GetType()==stToken::TokenComma);		}
			
		}
		
		if (i<numTris-1)
		{
			token = tokenParser.GetNextToken();		DBG_ASSERT(token->GetType()==stToken::TokenComma);
		}
	}
	token = tokenParser.GetNextToken();	DBG_ASSERT(token->GetType()==stToken::TokenSemiColon);

	token = tokenParser.GetNextToken();

	DBG_ASSERT((token->GetType()==stToken::TokenString) || (token->GetType()==stToken::TokenCloseB));

	ParseData(tokenParser, xBase);

	DBG_ASSERT(token->GetType()==stToken::TokenCloseB);
}

/******************************************************************************/

void ParseData(TokenParser& tokenParser, stXBase* xBase)
{
	stToken* token = tokenParser.GetToken();
	DBG_ASSERT(token);
	DBG_ASSERT(token->GetType()==stToken::TokenString);

	while (token->GetType()!=stToken::TokenCloseB)
	{
		int itemId = -1;

		switch (token->GetType())
		{
			case stToken::TokenString:
			{
				const char* str = token->m_data;
				DBG_ASSERT(str);

				itemId = GetXStringID(str);
				DBG_ASSERT(itemId>-1);
			}
			break;

			default: { DBG_HALT; }
		}

		switch (itemId)
		{
			// Global
			case X_HEADER:					ReadHEADER(tokenParser,					xBase);		break;
			case X_TEMPLATE:				ReadXTEMPLATE(tokenParser,				xBase);		break;
			case X_FRAME:				
			{
				stXFrame* xFrameParent = NULL;
				if (xBase->GetType()==X_FILE)  xFrameParent=&static_cast<stXFile*>(xBase)->m_frame;
				if (xBase->GetType()==X_FRAME) xFrameParent=static_cast<stXFrame*>(xBase);

				stXFrame* xFrame = new stXFrame();
				ReadXFRAME(tokenParser,xFrame);

				xFrameParent->AddChild(xFrame);

			}
			break;

			case X_ANIMATIONSET:
			{
				stXAnimSet* xAnimSet = new stXAnimSet();

				
				if (xBase->GetType()==X_FILE)
				{
					stXFile* xFile = static_cast<stXFile*>(xBase);

					if (xFile->m_animSet==NULL)
					{
						xFile->m_animSet = xAnimSet;
					}
					else
					{
						xFile->m_animSet->AddNext(xAnimSet);
					}
				}
				else if (xBase->GetType()==X_ANIMATIONSET)
				{
					stXAnimSet* xAnimSetParent = NULL;
					xAnimSetParent=static_cast<stXAnimSet*>(xBase);
					xAnimSetParent->AddNext(xAnimSet);
				}
				else
				{
					DBG_HALT;
				}
				
				

				ReadXANIMATIONSET(tokenParser,			xAnimSet);
			}
			break;

			case X_MATERIAL:
			{
				DBG_ASSERT(xBase->GetType()==X_FILE);

				stXFile* xFile = (stXFile*)tokenParser.GetData();
				DBG_ASSERT(xFile);

				stXMaterial* xMat = xFile->m_materialManager.AddMaterial();
				ReadXMATERIAL(tokenParser, xMat);
			}
			break;

			case X_MESH:
			{
				stXFrame* xFrameParent = NULL;
				if (xBase->GetType()==X_FILE)  xFrameParent=&static_cast<stXFile*>(xBase)->m_frame;
				if (xBase->GetType()==X_FRAME) xFrameParent=static_cast<stXFrame*>(xBase);

				stXMesh* xMesh = new stXMesh();
				ReadXMESH(tokenParser,xMesh);

				xFrameParent->AddMesh(xMesh);
			}
			break;

			// Only for XFrame
			case X_FRAMETRANSFORMMATRIX:	ReadXFRAMETRANSFORMMATRIX(tokenParser,	xBase);		break;

			// Only for MESH
			case X_MESHNORMALS:				ReadXMESHNORMALS(tokenParser,			xBase);		break;
			case X_MESHMATERIALLIST:		ReadXMESHMATERIALLIST(tokenParser,		xBase);		break;
			case X_MESHTEXTURECOORDS:		ReadXMESHTEXTURECOORDS(tokenParser,		xBase);		break;
			case X_SKINWEIGHTS:				ReadXSKINWEIGHTS(tokenParser,			xBase);		break;
			case X_XSKINMESHHEADER:			ReadXSKINMESHHEADER(tokenParser,		xBase);		break;
			case X_VERTEXDUPLICATIONINDICES:ReadXVERTEXDUPLICATIONINDICES(tokenParser, xBase);	break;

			// Only for XMaterial
			case X_TEXTUREFILENAME:			ReadXTEXTUREFILENAME(tokenParser,		xBase);		break;
			case X_EFFECTINSTANCE:			ReadXEFFECTINSTANCE(tokenParser,		xBase);		break;
			case X_EFFECTPARAMSTRING:		ReadXEFFECTPARAMSTRING(tokenParser,		xBase);		break;
			case X_EFFECTPARAMDWORD:		ReadXEFFECTPARAMDWORD(tokenParser,		xBase);		break;
			case X_EFFECTPARAMFLOATS:		ReadXEFFECTPARAMFLOATS(tokenParser,		xBase);		break;

			// Only XPatchMesh
			case X_PATCH:					ReadXPATCH(tokenParser,					xBase);		break;
			case X_PATCHMESH:				ReadXPATCHMESH(tokenParser,				xBase);		break;

			// Only XAnimation
			case X_ANIMATIONKEY:			DBG_HALT;	/*Animation Reads it*/					break;

			// Only AnimationSet
			case X_ANIMATION:				ReadXANIMATION(tokenParser,				xBase);		break;

			default: 
			{
				SkipBlock(tokenParser);
				DBG_HALT; 
			}
		}

		token = tokenParser.GetNextToken();
		if (token==NULL)
		{
			break;
		}

		DBG_ASSERT((token->GetType()==stToken::TokenString) || (token->GetType()==stToken::TokenCloseB));
	}

	token = tokenParser.GetToken();
	DBG_ASSERT(token->GetType()==stToken::TokenCloseB);
}



/******************************************************************************/

void SortMeshMaterials(stXMesh* mesh)
{

	DBG_ASSERT(mesh);

	// Speed up...sort the materials and there related tri faces in order so there
	// grouped

	stXMaterialList* matList = mesh->m_matList;
	//DBG_ASSERT(matList);

	if (matList)
	for (int i=0; i<matList->m_numIndexes; i++)
	{
		for (int k=i+1; k<matList->m_numIndexes; k++)
		{
			if (matList->m_indexes[k] < matList->m_indexes[i])
			{
				int matA = matList->m_indexes[i];
				int matB = matList->m_indexes[k];

				matList->m_indexes[i] = matB;
				matList->m_indexes[k] = matA;


				DBG_ASSERT(k>=0 && k<mesh->m_numTris);
				DBG_ASSERT(i>=0 && i<mesh->m_numTris);

				stXMesh::stTriData temp = mesh->m_tris[i];
				mesh->m_tris[i] = mesh->m_tris[k];
				mesh->m_tris[k] = temp;
			}
		}
	}

}

/******************************************************************************/

void SortMatierals(stXBase* xBase)
{
	DBG_ASSERT(xBase);
	DBG_ASSERT(xBase->GetType()==X_FRAME || xBase->GetType()==X_MESH);

	switch (xBase->GetType())
	{
		case X_FRAME:
		{
			stXFrame* xFrame = static_cast<stXFrame*>(xBase);
			DBG_ASSERT(xFrame);
			while (xFrame)
			{
				stXMesh* mesh = xFrame->m_mesh;
				while (mesh)
				{
					SortMatierals(mesh);
					mesh = mesh->m_next;
				}

				if (xFrame->m_child)
				{
					SortMatierals(xFrame->m_child);
				}
				xFrame = xFrame->m_next;
			}
		}
		break;

		case X_MESH:
		{
			stXMesh* xMesh = static_cast<stXMesh*>(xBase);
			DBG_ASSERT(xMesh);
			SortMeshMaterials(xMesh);
		}
		break;

		default: { DBG_HALT; }
	}
	
}


/******************************************************************************/


void LoadXTxtFile(IDirect3DDevice9* pDevice, stXFile* xFile, const char* fileName)
{
	FILE* fp = fopen(fileName, "r");
	DBG_ASSERT(fp);

	fseek(fp, 0, SEEK_END);
	long fsize = ftell(fp);

	char* fileData = new char[fsize+1];
	memset(fileData, 0, fsize+1);
	fseek(fp, 0, SEEK_SET);
	int bytesRead = 
	(int)fread(fileData, 1, fsize, fp);
	fclose(fp);

	if (fsize!=bytesRead)
	{
		fileData[bytesRead] = 0;
	}

	DBG_ASSERT(strlen(fileName)<128);
	strcpy_s(xFile->m_fileName, fileName);

	DBG_ASSERT(pDevice);
	xFile->m_pD3DDevice = pDevice;

	TokenParser tokenParser(fileData, fsize);
	tokenParser.SetData((void*)xFile);

	// Strip of the header line
	tokenParser.GetNextToken();
	ReadXOF(tokenParser);

	while (tokenParser.GetNextToken())
	{
		ParseData(tokenParser, xFile);
	}

	tokenParser.SetData(NULL);

	char folder[128];
	memset(folder, 0, sizeof(folder));
	strcpy_s(folder, fileName);
	int indx = (int)strlen(folder);
	while (indx>0 && folder[indx]!='\\') indx--;
	if (indx>1) folder[indx+1]='\0';


	xFile->m_materialManager.LoadTextures(pDevice, folder);


	delete fileData;
	fileData = NULL;


	// Optional - sort the mesh triangle indices into order so that when
	// they are rendered they render groups of materials together
	SortMatierals(&xFile->m_frame);
}





